#!/usr/bin/python3
import datetime as dt
import sys
import os
import re
from load_config import *
import solar as sl

if sys.platform == "win32":
    import ctypes

_sunrise_time = None
_sunset_time = None
_theme = None
_desktop = None
_config_file = "catin.config"


def prepare():
    global _sunrise_time, _sunset_time, _theme, _desktop
    default_latitude = 28.65630
    default_longitude = 77.45979
    default_utc = 8
    if os.path.exists(_config_file):
        config = load_config(_config_file)
    else:
        f = open(_config_file, "w")
        f.write("theme = the-beach\n")
        f.write("latitude = {}\n".format(default_latitude))
        f.write("longitude = {}\n".format(default_longitude))
        f.write("utc = {}\n".format(default_utc))
        f.write("desktop = gnome\n")
        f.close()
        config = {}
    _theme = config.get("theme", "the-beach")
    _desktop = config.get("desktop", "")
    sl.set_parameters(
        latitude=config.get("latitude", default_latitude),
        longitude=config.get("longitude", default_longitude),
        utc_offset=config.get("utc", default_utc),
        day_of_year=dt.datetime.now().timetuple().tm_yday,
    )
    _sunrise_time, _sunset_time = sl.get_sunrise_sunset_time()


def update_config_file():
    if not _theme:
        return
    f = open(_config_file, "w")
    f.write("theme = {}\n".format(_theme))
    f.write("latitude = {}\n".format(sl._latitude))
    f.write("longitude = {}\n".format(sl._longitude))
    f.write("utc = {}\n".format(sl._utc_offset))
    f.write("desktop = {}\n".format(_desktop))
    f.close()


"""
1 the brightest, noon
2 the darkest, midnight
3,4,5 bright increasing
6,7,8 dark increasing
"""


def time_period_quantify_8(now):
    global _sunrise_time, _sunset_time
    dt = (_sunset_time - _sunrise_time) / 2
    t1 = _sunrise_time + dt / 3 * 0.95
    t2 = _sunrise_time + dt * 2 / 3 * 0.93
    t3 = _sunset_time - dt * 2 / 3 * 0.95
    t4 = _sunset_time - dt / 3 * 0.93
    t5 = _sunset_time + dt / 3 * 0.5
    t6 = _sunrise_time - dt / 3 * 0.5
    if t2 <= now < t3:
        return 1
    if now >= t5 or now < t6:
        return 2
    if _sunrise_time <= now < t1:
        return 4
    if t1 <= now < t2:
        return 5
    if t3 <= now < t4:
        return 6
    if t4 <= now < _sunset_time:
        return 7
    if _sunset_time <= now < t5:
        return 8
    return 3


def time_period_quantify_5(now):
    global _sunrise_time, _sunset_time
    dt = (_sunset_time - _sunrise_time) / 2
    t1 = _sunrise_time + dt / 3 * 0.95
    t2 = _sunrise_time + dt * 2 / 3 * 0.93
    t3 = _sunset_time - dt * 2 / 3 * 0.95
    t4 = _sunset_time - dt / 3 * 0.93
    t5 = _sunset_time + dt / 3 * 0.5
    t6 = _sunrise_time - dt / 3 * 0.5
    if t2 <= now < t3:
        return 1
    if now >= t5 or now < t6:
        return 2
    if _sunrise_time <= now < t1:
        return 4
    if t1 <= now < t2:
        return 5
    if t3 <= now < t4:
        return 5
    if t4 <= now < _sunset_time:
        return 4
    if _sunset_time <= now < t5:
        return 3
    return 3


def time_period_quantify_3(now):
    global _sunrise_time, _sunset_time
    dt = (_sunset_time - _sunrise_time) / 2
    t1 = _sunrise_time + dt / 3 * 0.95
    t2 = _sunset_time - dt / 3 * 0.95
    t3 = _sunset_time + dt / 3 * 0.5
    t4 = _sunrise_time - dt / 3 * 0.5
    if t1 <= now < t2:
        return 1
    if now >= t3 or now < t4:
        return 2
    return 3


def time_period_quantify_2(now):
    global _sunrise_time, _sunset_time
    if _sunrise_time <= now < _sunset_time:
        return 1
    return 2


def printer(*args):
    print(*args, file=sys.stderr)


def get_current_wallpaper():
    SPI_GETDESKWALLPAPER = 0x0073
    MAX_PATH = 256
    wallpaper = ctypes.create_unicode_buffer(MAX_PATH)
    result = ctypes.windll.user32.SystemParametersInfoW(
        SPI_GETDESKWALLPAPER, MAX_PATH, wallpaper, 0
    )
    if result:
        return wallpaper.value
    else:
        raise ctypes.WinError()


def main():
    global _theme, _desktop
    pwd = os.path.expanduser(os.path.join("~", "catin"))
    os.chdir(pwd)
    prepare()
    flush_config = False
    if sys.platform == "linux" and not _desktop:
        xdg_desktop = os.environ.get("XDG_CURRENT_DESKTOP")
        if not xdg_desktop:
            printer("Desktop environment not found.\nPlease set it in the config file.")
            exit(1)
        xdg_desktop = xdg_desktop.lower() if xdg_desktop else ""
        if "gnome" in xdg_desktop:
            _desktop = "gnome"
        elif "mate" in xdg_desktop:
            _desktop = "mate"
        else:
            printer("Desktop environment '{}' not supported.".format(xdg_desktop))
            exit(1)
        flush_config = True
    if sys.platform == "linux" and _desktop not in "gnome mate".split():
        printer("Desktop environment '{}' not supported.".format(_desktop))
        exit(1)
    if len(sys.argv) > 1:
        _theme = sys.argv[1]
        flush_config = True
    _theme = _theme.strip().lower()
    theme_path = "{}/{}".format(pwd, _theme)
    if not os.path.exists(theme_path) or not os.path.isdir(theme_path):
        printer("Theme '{}' not found.".format(_theme))
        exit(1)
    if flush_config:
        update_config_file()
    p_wp = re.compile(r"^(\d+)\.(?:jpeg|jpg|png)$", re.I)
    wp_pictures = {}
    for name in os.listdir(theme_path):
        if not os.path.isfile("{}/{}".format(theme_path, name)):
            continue
        m = p_wp.match(name)
        if not m:
            continue
        wp_pictures[int(m.group(1))] = name
    terms = len(wp_pictures)
    if terms < 2:
        printer("The number of wallpapers should be at least 2.")
        exit(1)
    now = dt.datetime.now()
    wp = ""
    if sys.platform == "win32":
        wp = get_current_wallpaper()
    elif _desktop == "gnome":
        cmd = "gsettings get org.gnome.desktop.background picture-uri"
    elif _desktop == "mate":
        cmd = "gsettings get org.mate.background picture-filename"
    else:
        printer("Desktop environment '{}' not supported.".format(_desktop))
        exit(1)
    if sys.platform != "win32":
        wp = os.popen(cmd).read().strip().replace("'", "")
        if not p_wp.match(wp):
            wp = ""
    now_hour = now.hour + now.minute / 60
    if terms >= 8:
        next_wp_ind = time_period_quantify_8(now_hour)
    elif terms >= 5:
        next_wp_ind = time_period_quantify_5(now_hour)
    elif terms >= 3:
        next_wp_ind = time_period_quantify_3(now_hour)
    else:
        next_wp_ind = time_period_quantify_2(now_hour)
    if next_wp_ind not in wp_pictures:
        printer("No wallpaper found for the current time.")
        exit(1)
    next_wp = wp_pictures[next_wp_ind]
    if not next_wp:
        printer(
            "No wallpaper found for the current time. \nFile names should start with 1., 2., 3., ..."
        )
        exit(1)
    if wp == next_wp:
        exit(0)
    if sys.platform == "win32":
        ok = ctypes.windll.user32.SystemParametersInfoW(
            20, 0, os.path.join(pwd, _theme, next_wp), 0
        )
        if not ok:
            printer("Failed to set wallpaper.")
            exit(1)
        return
    if _desktop == "gnome":
        cmd = "gsettings set org.gnome.desktop.background picture-uri 'file://{}/{}/{}'".format(
            pwd, _theme, next_wp
        )
    else:
        cmd = "gsettings set org.mate.background picture-filename '{}/{}/{}'".format(
            pwd, _theme, next_wp
        )
    ok = os.system(cmd)
    if ok != 0:
        printer("Failed to set wallpaper.")
        exit(1)


if __name__ == "__main__":
    usage = "usage: python3 {} [theme]".format(sys.argv[0])
    if len(sys.argv) > 1:
        if sys.argv[1] in ["-h", "--help"]:
            printer(usage)
            exit(0)

    if sys.platform == "linux" and not os.environ.get("DBUS_SESSION_BUS_ADDRESS"):
        printer(
            "D-Bus address is not set. Is the script running in a desktop environment?"
        )
        exit(1)
    main()
